package model

import (
	"github.com/jmoiron/sqlx"
	"time"
	"zimuzu_cvn_web_api/config"
	"zimuzu_cvn_web_api/pkg/e"
	"zimuzu_cvn_web_api/pkg/errno"
)

type NodeLoginV2Params struct {
	UserName string `form:"username" json:"username"`
	Password string `form:"password" json:"password"`
	Mac      string `form:"mac" json:"mac"`
	Version  string `form:"version" json:"version"`
	HostName string `form:"hostname" json:"hostname"`
	Ips      []IpsListParam
}

type IpsListParam struct {
	Mac    string `json:"mac"`
	Ip     string `json:"ip"`
	IsUsed bool   `json:"isUsed"`
}

type UserLoginResponse struct {
	Uid      int64  `db:"uid,omitempty" form:"uid" json:"uid"`
	Password string `db:"password" form:"password" json:"name"`
	Salt     string `db:"salt" form:"salt" json:"salt"`
}

type LoginRequest struct {
	Uid    int64  `json:"uid"`
	NodeId int64  `json:"node_id"`
	Token  string `json:"token,omitempty"`
	Name   string `json:"name,omitempty"`
}

type UserToken struct {
	Id               int    `db:"id,omitempty" json:"id,omitempty"`
	Uid              int64  `db:"uid" json:"uid"`
	Token            string `db:"token" json:"token"`
	DateLine         int64  `db:"dateline,omitempty" json:"dateline,omitempty"`
	Client           int    `db:"client" json:"client"`
	RegisterRationId string `db:"registration_id" json:"registration_id"`
}

type NodeStatusReportParams struct {
	Uid     int64  `form:"uid" json:"uid"`
	NodeId  string `form:"node_id" json:"node_id"`
	NatType int    `form:"nat_type" json:"nat_type"`
	List    []ReportListParams
}
type ReportListParams struct {
	Source   int   `form:"type" json:"type"`
	Status   int   `form:"status" json:"status"`
	FreeSize int64 `form:"free_size" json:"free_size"`
}

// 流量上报接口
// Auth: hzp
func CreateReportRecord(Id string, NodeId, t int64, source int) (err error) {

	var count int
	err = sqlx.Get(config.C.DB.DB, &count, "SELECT COUNT(*) FROM mg_flows_report WHERE report_id = ? "+
		"AND node_id = ? AND source = ?", Id, NodeId, source)
	if err == nil && count > 0 {
		return nil
	}

	res := sqlx.MustExec(config.C.DB.DB, "INSERT INTO mg_flows_report (`node_id`, `source`, `report_id`, "+
		"`create_time`) VALUES (?, ?, ?, ?)", NodeId, source, Id, t)
	_, err = res.LastInsertId()
	if err != nil {
		e.Log("err", err.Error())
		return errno.DbError
	}
	return
}

// 校验节点是否存在
// Auth: hzp
func CheckFlowsNode(Uid int64, typeInt int, mac, ipStr string) (NodeId int64, err error) {

	// 为了阳术国接口做转换
	var nodeType int
	if typeInt == 1 {
		nodeType = 2
	} else {
		nodeType = 3
	}
	nodeInfo, err := GetMgNodeInfoByUidS(Uid, mac, nodeType)
	if err != nil {
		return 0, err
	}
	if ipStr != nodeInfo.PublicIp || len(nodeInfo.Isp) < 1 {
		if len(ipStr) < 3 {
			e.Log("info", "ip地址异常，不支持更新")
			return 0, errno.RecordError
		}
		// 需要更新节点的 公网ip数据
		nodeIpsData, err := GetISPByIp(ipStr)
		if err != nil {
			e.Log("info", "运营信息获取失败：")
			e.Log("info", nodeIpsData)
			e.Log("info", err.Error())
			return 0, err
		}
		err = UpdateMgNodeIpsData(nodeInfo.NodeId, ipStr, nodeIpsData)
		if err != nil {
			e.Log("info", "运营信息更新失败："+err.Error())
			return 0, err
		}
	}
	if nodeInfo.NodeId > 0 {
		return nodeInfo.NodeId, nil
	}
	return 0, errno.RecordError
}

// 新增用户token
func AddUserToken(qi *UserToken) error {
	db := config.C.DB.DB
	qi.DateLine = time.Now().Unix()
	_, err := sqlx.NamedExec(db,
		`insert into user_token(uid, token, dateline, client, registration_id) values (:uid, :token, :dateline, :client, :registration_id)`,
		*qi)
	if err != nil {
		return err
	}
	return nil
}

func CreateNode(Uid int64, Name, Mac string) (nodeId int64, nodeName string, err error) {

	count := 0
	err = sqlx.Get(config.C.DB.DB, &count, "SELECT count(*) FROM mg_node WHERE uid = ? AND mac = ? AND `type` = 2 AND `status` < 2", Uid, Mac)
	if err != nil {
		return 0, Name, err
	}
	if count > 0 {
		res, err := GetNodeIdByUidMac(Uid, Mac)
		if err != nil {
			return 0, Name, err
		}
		return res.NodeId, res.Name, err
	}

	res := sqlx.MustExec(config.C.DB.DB, "INSERT INTO mg_node(uid, name, mac, status, create_time, type)"+
		" values (?, ?, ?, 0, NOW(), 2)", Uid, Name, Mac)
	re, err := res.LastInsertId()
	if err != nil {
		return 0, Name, err
	}
	if re > 0 {
		return re, Name, nil
	}
	return re, Name, nil
}

func GetNodeIdByUidMac(Uid int64, mac string) (res NodeMacModel, err error) {

	err = sqlx.Get(config.C.DB.DB, &res, "SELECT node_id, name from mg_node where uid = ? and mac = ?", Uid, mac)
	if err != nil {
		return res, err
	}

	return res, nil
}

// 校验uid+nodeId对应的节点数据是否存在
// Auth: hzp
type CheckNodeInfo struct {
	HistoryOnlineTime string `json:"history_online_time" db:"history_online_time"`
	ISP               string `json:"isp" db:"isp"`
	OnlineTime        int    `json:"online_time" db:"online_time"`
	Status            int    `json:"status" db:"status"`
	NatType           int    `json:"nat_type" db:"nat_type"`
}

func CheckNodeByUidAndNodeId(Uid int64, NodeId string) (res CheckNodeInfo, err error) {
	var count int
	err = sqlx.Get(config.C.DB.DB, &count, "SELECT Count(*) from mg_node where uid = ? and node_id = ?", Uid, NodeId)
	if err != nil {
		return res, err
	}
	if count < 1 {
		return res, errno.RecordError
	}
	err = sqlx.Get(config.C.DB.DB, &res, "SELECT IFNULL(status, 0) as status, online_time, nat_type, isp, history_online_time "+
		" FROM mg_node where uid=? AND node_id=?", Uid, NodeId)
	if err != nil {
		return res, err
	}
	return res, nil
}

// 根据Uid+NodeId获取到对应的节点信息
// Auth: hzp
func GetNodeInfoByUidAndNodeId(Uid, NodeId int64) (res UserNodeInfo, err error) {
	err = sqlx.Get(config.C.DB.DB, &res, "SELECT node_id, status, type, IFNULL(token_status, 1) as token_status"+
		" FROM mg_node where uid=? AND node_id=?", Uid, NodeId)
	if err != nil {
		return res, err
	}
	return res, nil
}

// 检查nodeId+Source对应的记录是否存在
// Auth: hzp
type NodeSourceParams struct {
	NodeId int64 `db:"node_id" form:"node_id" json:"node_id"`
	Source int   `db:"source" form:"source" json:"source"`
	Off    int   `db:"off" form:"off" json:"off"`
}

func CheckRecordByNodeIdAndSource(NodeId int64, Source int) (res NodeSourceParams, err error) {

	var count int
	db := config.C.DB.DB
	err = sqlx.Get(db, &count, "Select count(*) FROM mg_node_source Where node_id = ? and source = ?", NodeId, Source)
	if err != nil {
		return res, err
	}
	if count < 1 {
		return res, errno.RecordError
	}

	err = sqlx.Get(config.C.DB.DB, &res, "SELECT node_id, source, off from mg_node_source where node_id = ? and source = ?", NodeId, Source)
	if err != nil {
		return res, err
	}
	return res, nil
}

// 插入记录 mg_node_source
// Auth: hzp
func AddNodeSourceRecord(NodeId int64, Source, Off int) (err error) {
	res := sqlx.MustExec(config.C.DB.DB, "INSERT INTO mg_node_source(node_id, source, off)"+
		" values (?, ?, ?)", NodeId, Source, Off)
	re, err := res.LastInsertId()
	if err != nil {
		return err
	}
	if re > 0 {
		return nil
	}
	return err
}

// 更新数据 mg_node_source
// Auth: hzp
func UpdateNodeSourceRecord(NodeId int64, Source, Off int) (err error) {
	res := sqlx.MustExec(config.C.DB.DB, "UPDATE mg_node_source SET off = ? WHERE node_id = ? AND source = ?", Off, NodeId, Source)
	_, err = res.RowsAffected()
	if err != nil {
		return err
	}
	return nil
}

// 第三方流量数据
type TailWuFlowParams struct {
	Id     string `form:"id" json:"id"`
	PId    string `form:"pid" json:"pid"`
	Upload TailWuUpload
}
type TailWuUpload struct {
	Flow []TailWuFlow
}
type TailWuFlow struct {
	Time int64   `form:"ts" json:"ts"`
	Flow float64 `form:"bytes" json:"bytes"`
}

type ReportDB struct {
	NodeId   int64  `db:"node_id" json:"node_id"`
	ReportId string `db:"report_id" json:"report_id"`
	Source   int    `db:"source" json:"source"`
	Type     int    `db:"type" json:"type"`
}

// 跟进上报ID获取到对应的节点信息
func GetAllNodeIdForReport() (res []ReportDB, err error) {
	err = sqlx.Select(config.C.DB.DB, &res, "SELECT node_id,report_id,source,type FROM mg_flows_report WHERE 1")
	if err != nil {
		return res, err
	}
	return res, nil
}

type HeatDistributionStruct struct {
	Name     string `form:"name" json:"name"`
	Selected bool   `form:"selected" json:"selected"`
	Value    int    `form:"value" json:"value"`
}

func GetHeatDistributionDb() (res []HeatDistributionStruct, err error) {
	err = sqlx.Select(config.C.DB.DB, &res, "SELECT province as `name`, COUNT(*) as `value` FROM mg_node "+
		"WHERE `status` <> 2 AND country = '中国' GROUP BY province ")
	if err != nil {
		return res, err
	}
	return res, nil
}

// 更新节点在线状态
// Auth: hzp
func UpdateMgNodeStatus(NodeId string, Status, updateOnlineTime, NatType int, historyOnlineTime string, freeSize int64) (err error) {
	if updateOnlineTime <= 0 {
		return nil
	}
	res := sqlx.MustExec(config.C.DB.DB, "UPDATE mg_node SET `status` = ?, online_time =?, process = 7, nat_type = ?, "+
		"offline = 0, history_online_time = ?, storage_available = ? WHERE node_id = ? ", Status, updateOnlineTime,
		NatType, historyOnlineTime, freeSize, NodeId)
	_, err = res.RowsAffected()
	if err != nil {
		return err
	}
	return nil
}

// 获取多条线路昨日流量
// Auth: hzp
func GetMultipleFlowsData(Source int) (up float64, err error) {
	err = sqlx.Get(config.C.DB.DB, &up, "SELECT sum(up) as up FROM mg_node_flow WHERE `status` = 0 AND "+
		" `time` >= UNIX_TIMESTAMP(CAST(SYSDATE()AS DATE) - INTERVAL 1 DAY) AND "+
		" `time` < UNIX_TIMESTAMP(CAST(SYSDATE()AS DATE)) AND source = ?", Source)
	if err != nil {
		return up, err
	}
	return up, nil
}

type MultipleNodeFlows struct {
	NodeId int64   `json:"node_id" db:"node_id"`
	Source int     `json:"source" db:"source"`
	Type   int     `json:"type" db:"type"`
	Up     float64 `json:"up" db:"up"`
}

func GetMultipleNodeFlowsData() (res []MultipleNodeFlows, err error) {
	err = sqlx.Select(config.C.DB.DB, &res, "SELECT node_id, `source`, `type`, sum(up) as up FROM mg_node_flow "+
		" WHERE `status` = 0 AND `time` >= UNIX_TIMESTAMP(CAST(SYSDATE()AS DATE) - INTERVAL 1 DAY) AND "+
		" `time` < UNIX_TIMESTAMP(CAST(SYSDATE()AS DATE)) GROUP BY node_id, source")
	if err != nil {
		return res, err
	}
	return res, nil
}

type ProfitSourceList struct {
	Source      int     `json:"source" db:"source"`
	Switch      int     `json:"switch" db:"switch"`
	SettlePrice float64 `json:"settle_price" db:"settle_price"`
}

// mg_profit_source
// 线路配置
func GetProfitSourceConfig() (res []ProfitSourceList, err error) {
	err = sqlx.Select(config.C.DB.DB, &res, "SELECT source, switch, settle_price FROM mg_profit_source Where 1 ")
	if res != nil {
		return res, err
	}
	return res, nil
}
